package com.google.code.openperfmon.db;

import java.io.InputStream;
import java.util.Properties;

import org.hibernate.Session;
import org.hibernate.SessionFactory;
import org.hibernate.Transaction;
import org.hibernate.cfg.AnnotationConfiguration;
import org.hibernate.tool.hbm2ddl.SchemaExport;
import org.hibernate.tool.hbm2ddl.SchemaUpdate;

import com.opensymphony.xwork2.ActionContext;

public class DBManager {
	public static final boolean USE_CACHE = Boolean.getBoolean("dbmanager.usecache");
	private static final Properties properties;
	
	static {
		try {
			properties = new Properties();
			InputStream is = DBManager.class.getResourceAsStream("/database.properties"); 
			properties.load(is);
			is.close();
		} 
		catch (Exception e) {
			e.printStackTrace();
			throw new ExceptionInInitializerError(e);
		}
		
	}
	
	static Properties getProperties() {
		return properties;
	}

	public static Session get() {
		Session ses = (Session)ActionContext.getContext().get(DBManager.class.getName());
		if (ses == null) {
			ses = getFactory().openSession(); 
			ActionContext.getContext().put(DBManager.class.getName(), ses);
		}
		return ses;
	}
	
	public static void cleanup() {
		ActionContext ctx = ActionContext.getContext();
		Session ses = (Session)ctx.get(DBManager.class.getName());
		if (ses != null) {
			ses.close();
			ctx.put(DBManager.class.getName(), null);
		}
	}
	
	public static void updateSchema() {
		initFactory();
		SchemaUpdate update = new SchemaUpdate(cfg);
		update.execute(false, true);
	}
	
	public static void exportSchema(String file) {
		initFactory();
		SchemaExport export = new SchemaExport(cfg);
		export.setDelimiter(";");
		export.setOutputFile(file);
		export.drop(true, false);
		export.create(true, false);
	}
	
	public static interface Do {
		void perform(Session session);
	}
	
	/**
	 * TX_REQUIRED pattern
	 */
	public static void transact(Do callback) {
		Session ses = get();
    	Transaction tx = ses.getTransaction();
    	boolean newTx = !tx.isActive(); 
    	if (newTx) tx.begin();
		try {
			callback.perform(ses);
			ses.flush();
    		if (newTx) tx.commit();
		}
		catch (RuntimeException e) {
			tx.rollback();
			cleanup();
			throw e;
		}
	}
	
	private static AnnotationConfiguration cfg = null;
	private static SessionFactory factory = null;
	private static SessionFactory getFactory() {
		if (factory == null) initFactory();
		return factory;
	}
	
	private static synchronized void initFactory() {
		if (factory == null) {
			cfg = new AnnotationConfiguration();
			cfg.configure();
			cfg.setProperties(properties);
			factory = cfg.buildSessionFactory();
		}
	}
}
